﻿using System;
using System.Web.Mvc;
using System.Linq;
using System.Collections.Generic;
using Sendz.Domain;
using Sendz.Model;
using Sendz.WebUI.Authorization;
using Sendz.WebUI.Helpers;
using Sendz.WebUI.Models;
using System.Web.Security;
using System.Text.RegularExpressions;
using System.IO;
using System.Text;
using iTextSharp.text.pdf;
using iTextSharp.text;
using System.Globalization;
using Microsoft.Security.Application;
using System.Web;
using System.Configuration;

namespace Sendz.WebUI.Controllers
{
    // Ref: http://stackoverflow.com/questions/759519/c-centralizing-repeating-viewdata-in-mvc
    [UserInfo] // Reference UserHelpers.cs for attribute override method; allows global user parameter access
    public class FormController : AjaxFriendlyController
    {
        #region Repository injection //////////////////////////////////

        // Aggregate repositories, injected by container factory in /Infrastructure
        private readonly IUserRepository dbUser;
        private readonly IIdentityRepository dbIdentity;
        private readonly IFormRepository dbForm;
        private readonly IAutoResponderRepository dbAutoResponder;
        public FormController(IUserRepository dbUser, IIdentityRepository dbIdentity, IFormRepository dbForm, IAutoResponderRepository dbAutoResponder)
        {
            this.dbUser = dbUser;
            this.dbIdentity = dbIdentity;
            this.dbForm = dbForm;
            this.dbAutoResponder = dbAutoResponder;
        }

        #endregion

        #region Action: List Index ////////////////////////////

        [Authorize]
        public ViewResult List()
        {
            // Retrieve current, logged-in user
            var user = Membership.GetUser(true) as CustomMembershipUser;
            // Todo: manage this workflow better... use a more abstracted intervention strategy
            var thisUser = dbUser.GetUserByKey((Guid)user.ProviderUserKey);
            var userForms = dbForm.GetFormsByUserKey((Guid)user.ProviderUserKey);
            var timeDiff = DateTime.Now.Subtract(thisUser.CreatedOn);
            if (userForms.Count == 0 && ((timeDiff.Days * 1440 + timeDiff.Hours * 60 + timeDiff.Minutes) <= 30))
                ViewData["IsNewUser"] = true;
            else
                ViewData["IsNewUser"] = false;
            ViewData["DomainShort"] = ConfigurationManager.AppSettings.Get("AppDomainShort") + ConfigurationManager.AppSettings.Get("AppRootPath");
            return View(userForms);
        }

        #endregion

        #region Action: Create (Uses Edit) ////////////////////////////

        [Authorize]
        [HttpGet]
        public ViewResult Create()
        {
            // Retrieve current, logged-in user
            var user = Membership.GetUser(true) as CustomMembershipUser;
            // Use a common helper to fill the options since the model binder uses this too
            var formDataHelpers = new Sendz.WebUI.Helpers.FormDataHelpers();
            ViewData["AutoResponders"] = formDataHelpers.GetAutoResponders(null, (Guid)user.ProviderUserKey);
            // Set a reference point to this being a new form to hide the fields edit toggle
            ViewData["IsNewForm"] = true;
            ViewData["TrueFalseList"] = _trueFalseList;
            // Process new forms through the HttpPost handler for the "Edit" action
            return View("Edit", new Form((Guid)user.ProviderUserKey));
        }

        #endregion

        #region Action: Edit ////////////////////////////

        private List<SelectListItem> _trueFalseList = new List<SelectListItem>() { new SelectListItem { Text = "Yes", Value = "True" }, new SelectListItem { Text = "No", Value = "False" } };

        [Authorize]
        [HttpGet]
        public ViewResult Edit(Guid id)
        {
            var user = Membership.GetUser(true) as CustomMembershipUser;
            var thisForm = dbForm.GetFormByKey(id);
            // Use a common helper to fill the options since the model binder uses this too
            var formDataHelpers = new Sendz.WebUI.Helpers.FormDataHelpers();
            ViewData["AutoResponders"] = formDataHelpers.GetAutoResponders(thisForm, (Guid)user.ProviderUserKey);
            // Specify a default value for existing forms
            ViewData["IsNewForm"] = false;
            ViewData["TrueFalseList"] = _trueFalseList;
            return View(thisForm);
        }

        [Authorize]
        [HttpPost]
        [ValidateInput(false)] // Used to allow WYSIWYG editor posts
        public ActionResult Edit(Form form, bool isNewForm, bool saveClose)
        {
            // Cleanse the returned HTML (since we allow an editor for this); do pre .IsValid since error results need to re-display this
            form.CompletionMessage = AntiXss.GetSafeHtmlFragment(form.CompletionMessage); // form.CompletionMessage = AntiXss.GetSafeHtml(HttpUtility.UrlDecode(form.CompletionMessage, System.Text.Encoding.Default));
            if (ModelState.IsValid)
            {
                // Set a short path for new forms
                if (isNewForm)
                {
                    var textHelp = new TextHelpers();
                    form.ShortPath = textHelp.RandomString(7);
                }
                // Save the new form (save method works for new or existing forms)
                if (dbForm.SaveForm(form))
                {
                    // Confirmation message valid for a single redirect
                    TempData["Message"] = (isNewForm) ?
                        "Your form was created, now add some fields" :
                        "Your form was successfully saved";
                    if (saveClose)
                        return Redirect("/Form/List");
                    TempData["IsNewForm"] = isNewForm;
                    return Redirect("/Form/EditFields/" + form.FormKey);
                }
            }
            // Otherwise, reload the view (& display errors)
            var user = Membership.GetUser(true) as CustomMembershipUser;
            // Use a common helper to fill the options since the model binder uses this too
            var formDataHelpers = new Sendz.WebUI.Helpers.FormDataHelpers();
            ViewData["AutoResponders"] = formDataHelpers.GetAutoResponders(form, (Guid)user.ProviderUserKey);
            ViewData["IsNewForm"] = isNewForm;
            ViewData["TrueFalseList"] = _trueFalseList;
            return View(form);
        }

        #endregion

        #region Action: EditFields ////////////////////////////

        // View for editing fields for a specific form, it seems to be easier to do this on its own screen
        [Authorize]
        [HttpGet]
        public ViewResult EditFields(Guid id)
        {
            var form = dbForm.GetFormByKey(id);
            // Return a single form field if there aren't any, for use as a starting point (reference FormKey!) 
            // Default the first field to an email field to make the AutoResponder process easier (though the inline message only displays once)
            var fields = (form.FormFields.Count > 0) ? form.FormFields.OrderBy(ff => ff.SortOrder).ToList() : new List<FormField> { new FormField() { ListEnum = "field_open_textbox_email" } };
            // Set some necessary ViewData stuff to reference
            if (form.FormFields.Count == 0)
                ViewData["IsNewForm"] = true;
            // Needed for links in view
            ViewData["FormKey"] = id;
            // Basic list for drop-down
            ViewData["FieldTypes"] = dbForm.GetFieldTypes();
            return View(fields);
        }

        [Authorize]
        [HttpPost]
        public ActionResult EditFields(List<FormField> formFields, Guid id)
        {
            if (ModelState.IsValid)
            {
                var origForm = dbForm.GetFormByKey(id);
                foreach (var origField in origForm.FormFields)
                {
                    // Remove any non-returned fields (they used to be here, now they are not)
                    if (formFields.FirstOrDefault(ff => ff.FormFieldKey == origField.FormFieldKey) == null)
                        dbForm.RemoveField(origField.FormFieldKey);
                }
                // If all form fields are deleted, there's nothing to add or edit...
                if (formFields != null)
                {
                    var sortOrder = 1;
                    var saveSuccess = true;
                    foreach (var formField in formFields)
                    {
                        formField.SortOrder = sortOrder++;
                        // Save the field (add or edit)
                        if (!dbForm.SaveField(id, formField))
                            saveSuccess = false;
                    }
                    if (saveSuccess)
                    {
                        // Todo: manage this workflow better... use a more abstracted intervention strategy
                        // Check if they're a new user and if so, route them & alert them to create an autoresponder
                        var user = Membership.GetUser(true) as CustomMembershipUser;
                        var myAutoResponders = dbAutoResponder.GetAutoRespondersByUserKey((Guid)user.ProviderUserKey);
                        var timeDiff = DateTime.Now.Subtract(origForm.CreatedOn);
                        if (myAutoResponders.Count == 0 && ((timeDiff.Days * 1440 + timeDiff.Hours * 60 + timeDiff.Minutes) <= 30))
                        {
                            TempData["Message"] = "Excellent, now you have a form, try creating an AutoResponder!";
                            return Redirect("/AutoResponder/List/");
                        }
                        TempData["Message"] = "Your form's fields were successfully saved";
                        return Redirect("/Form/List");
                    }
                }
            }
            // Rebuild ViewData on error (!)
            // Set some necessary ViewData stuff to reference
            // Needed for links in view
            ViewData["FormKey"] = id;
            // Basic list for drop-down
            ViewData["FieldTypes"] = dbForm.GetFieldTypes();
            return View(formFields);
        }

        #endregion

        #region Action: Display ////////////////////////////

        [HttpGet]
        public ViewResult Display(string id, string shortpath)
        {
            Form form = null;
            if (!string.IsNullOrEmpty(shortpath))
            {
                form = dbForm.GetFormByShortPath(shortpath);
            }
            else
            {
                var thisGuid = Guid.Empty;
                if (Guid.TryParse(id, out thisGuid))
                    form = dbForm.GetFormByKey(thisGuid);
            }
            if (form != null)
            {
                var viewModel = new List<FormFieldViewModel>();
                var newViewModel = new List<object>();
                foreach (var field in form.FormFields)
                {
                    // Use a common helper to fill the options since the model binder uses this too
                    var formDataHelpers = new Sendz.WebUI.Helpers.FormDataHelpers();
                    // Get required error message template
                    var thisFieldType = dbForm.GetFieldTypeByKey(field.FieldTypeKey);
                    // Create arrays with a blank value as default (since we use value[0] etc.)
                    viewModel.Add(new FormFieldViewModel
                    {
                        FormFieldKey = field.FormFieldKey,
                        Name = field.Name,
                        Value = new string[] { string.Empty },
                        ListEnum = field.ListEnum,
                        Options = formDataHelpers.GetFieldOptions(field)
                    });
                }
                ViewData["FormKey"] = form.FormKey;
                ViewData["FormName"] = form.Name;
                return View(viewModel);
            }
            return null; // Todo: may later wish to make this standard error page
        }

        [HttpPost]
        public ActionResult Display(IEnumerable<FormFieldViewModel> formresponses, Guid formKey)
        {
            if (ModelState.IsValid)
            {
                var thisForm = dbForm.GetFormByKey(formKey);
                var thisUser = dbUser.GetUserByKey(thisForm.UserKey);
                if (thisUser.ResponsesRemaining > 0)
                {
                    var emailHelper = new EmailHelpers();
                    // Decrement remaining responses
                    thisUser.ResponsesRemaining -= 1;
                    dbUser.UpdateUserResponses(thisUser.UserKey, thisUser.ResponsesRemaining);
                    // Give an alert to the user they should purchase more response submissions
                    if (thisUser.ResponsesRemaining == 5 || thisUser.ResponsesRemaining == 25)
                    {
                        // Todo: move this text to resource files or, at least, configurable/marketing-managed values
                        emailHelper.SendEmail(ConfigurationManager.AppSettings.Get("FromAddressAdmin"), thisUser.Email, "You only have " + thisUser.ResponsesRemaining + " Frontdesk responses remaining!", "Really! You've only got " + thisUser.ResponsesRemaining + " responses left before your Frontdesk account stops working. Please be sure to inquire about getting additional responses as soon as possible to avoid running out, and risk losing the chance to collect valuable data!", null, false);
                    }
                    var responseItems = new List<Tuple<Guid, string>>();
                    // Holding value in case an alert is configured to send
                    var responseBody = new StringBuilder();
                    foreach (var response in formresponses)
                    {
                        // Our ViewModel returns an array to accomodate multiple-selection values, joined with ","
                        if (response.Value != null)
                        {
                            var thisResponse = string.Join("; ", response.Value).ToString();
                            responseItems.Add(new Tuple<Guid, string>(response.FormFieldKey, thisResponse));
                            responseBody.Append("<strong>" + response.Name + "</strong>: " + thisResponse + "<br />");
                        }
                    }
                    var responseKey = dbForm.CreateResponseWithItems(formKey, responseItems);
                    if (responseKey != Guid.Empty)
                    {
                        // Send the autoresponder if there is one
                        var thisResponse = dbForm.GetResponseByKey(responseKey);
                        if (thisResponse.IdentityKey != null && thisForm.AutoResponderKey != null)
                        {
                            var thisAutoResponder = dbAutoResponder.GetAutoResponderByKey((Guid)thisForm.AutoResponderKey);
                            if (thisAutoResponder != null)
                            {
                                var thisIdentity = dbForm.GetIdentityByKey((Guid)thisResponse.IdentityKey);
                                // Ensure the email from address was validated
                                if (dbUser.IsEmailValidated(thisUser.UserKey, thisAutoResponder.FromEmail))
                                {
                                    // If wildcarding was used, replace the values directly from the formresponse object (List<FormFieldViewModel>)
                                    if (thisAutoResponder.Body.IndexOf("[%") > -1)
                                    {
                                        foreach (var field in dbForm.GetFieldsByFormKey(formKey))
                                        {
                                            // Todo: move this to a DRY function
                                            thisAutoResponder.Subject = thisAutoResponder.Subject.Replace("[%" + field.Name + "%]", string.Join("; ", formresponses.Single(r => r.FormFieldKey == field.FormFieldKey).Value).ToString());
                                            thisAutoResponder.Body = thisAutoResponder.Body.Replace("[%" + field.Name + "%]", string.Join("; ", formresponses.Single(r => r.FormFieldKey == field.FormFieldKey).Value).ToString());
                                        }
                                    }
                                    // Append any attachments
                                    var attachments = dbAutoResponder.GetAttachments(thisAutoResponder.AutoResponderKey);
                                    var attachmentList = new List<string>();
                                    if (attachments != null)
                                    {
                                        foreach (var attachment in attachments)
                                            attachmentList.Add(attachment.FilePath);
                                    }
                                    emailHelper.SendEmail(thisAutoResponder.FromEmail, thisIdentity.Email, thisAutoResponder.Subject, thisAutoResponder.Body, attachmentList, false);
                                    dbForm.LogAutoResponse(thisAutoResponder.AutoResponderKey, thisIdentity.IdentityKey);
                                }
                                else
                                {
                                    // Send a nag to the account holder to validate the email from address
                                    emailHelper.SendEmail(ConfigurationManager.AppSettings.Get("FromAddressAdmin"), thisUser.Email, "Your autoresponder couldn't be sent!", "Uh oh! The autoresponder '" + thisAutoResponder.Name + "' should have been sent to '" + thisIdentity.Email + "' when they filled out your form '" + thisForm.Name + "', but it couldn't be sent because you haven't validated the email from-address in that autoresponder.<br /><br />If you created your autoresponder with a 'fake' email address, <strong>update your autoresponder now</strong> and then check that email address and ensure you click the validation link that is sent to you!", null, false);
                                }
                            }
                        }
                        // If this form gets an alert sent upon completion, do that
                        if (thisForm.AlertOnComplete)
                            emailHelper.SendEmail(ConfigurationManager.AppSettings.Get("FromAddressAdmin"), thisUser.Email, "Your form '" + thisForm.Name + "' has a new response", "The following form response was received at " + DateTime.Now + ":<br /><br />" + responseBody.ToString(), null, false);
                        if (thisForm.IsRedirectOnComplete)
                            return Redirect(thisForm.RedirectURL);
                        else
                        {
                            TempData["Message"] = thisForm.CompletionMessage;
                            return Redirect("/Form/DisplayCompleted");
                        }
                    }
                    else
                    {
                        TempData["Message"] = "There was an error saving your response, please try again later";
                    }
                }
                else
                {
                    TempData["Message"] = "Sorry, this response could not be saved because this Frontdesk account is inactive";
                }
            }
            ViewData["FormKey"] = formKey;
            return View(formresponses);
        }

        [HttpGet]
        public ViewResult DisplayCompleted()
        {
            return View();
        }

        #endregion

        #region Action: Remove ////////////////////////////

        [Authorize]
        [HttpGet]
        public ActionResult Remove(Guid id)
        {
            if (dbForm.RemoveForm(id))
            {
                TempData["Message"] = "Your form was successfully removed";
            }
            return Redirect("/Form/List");
        }

        #endregion

        #region Action: Export ////////////////////////////

        private enum TableType { StringWriter = 1, PdfPTable = 2 }

        private object BuildTable(Guid formKey, TableType thisType, List<Font> fonts = null)
        {
            var responseBlock = dbForm.GetResponsesByFormKey(formKey);
            if (responseBlock != null)
            {
                var formFields = dbForm.GetFieldsByFormKey(formKey);
                if (formFields != null)
                {
                    // Set some common/repeat variables /////////////////////
                    var stringWriter = new StringWriter();
                    // Set the count to +1 to include the response time col
                    var colCount = formFields.Count + 1;
                    var table = new PdfPTable(colCount);
                    var outputRow = new StringBuilder();
                    var delimiter = string.Empty;
                    /////////////////////////////////////////////////////////

                    if (thisType == TableType.StringWriter)
                    {
                        foreach (var header in formFields)
                        {
                            outputRow.Append(delimiter + "\"" + header.Name + "\"");
                            delimiter = ","; // Set the delimiter so it will appear for the next field
                        }
                        outputRow.Append(delimiter + "\"Response Time\"");
                        stringWriter.WriteLine(outputRow);
                    }
                    else
                    {
                        var cell = new PdfPCell(new Phrase("Export created on " + DateTime.Now, fonts.Single(f => f.Style == Font.ITALIC))) { Colspan = colCount, HorizontalAlignment = 1 };
                        table.AddCell(cell);
                        foreach (var header in formFields)
                            table.AddCell(new Phrase(header.Name, fonts.Single(f => f.Style == Font.BOLD)));
                        table.AddCell(new Phrase("Response Time", fonts.Single(f => f.Style == Font.BOLD)));
                    }
                    foreach (var response in responseBlock)
                    {
                        // Reset our output tools
                        outputRow = new StringBuilder();
                        delimiter = string.Empty;
                        // Return, per response, the response items and build the output in the correct field order
                        var responseItems = dbForm.GetResponseItemsByKey(response.ResponseKey);
                        if (responseItems != null)
                        {
                            foreach (var formField in formFields)
                            {
                                var outputItem = responseItems.FirstOrDefault(oi => oi.FormFieldKey == formField.FormFieldKey);
                                // We now have a valid item to append to our row or not
                                if (outputItem != null)
                                {
                                    if (thisType == TableType.StringWriter)
                                        outputRow.Append(delimiter + "\"" + outputItem.Entry + "\"");
                                    else
                                        table.AddCell(new Phrase(outputItem.Entry, fonts.Single(f => f.Style == Font.NORMAL)));
                                }
                                else
                                {
                                    // Otherwise, set a blank response for this column
                                    if (thisType == TableType.StringWriter)
                                        outputRow.Append(delimiter + "\"\"");
                                    else
                                        table.AddCell(new Phrase(string.Empty, fonts.Single(f => f.Style == Font.NORMAL)));
                                }
                                delimiter = ","; // Set the delimiter so it will appear for the next field
                            }
                            if (thisType == TableType.StringWriter)
                            {
                                outputRow.Append(delimiter + "\"" + response.CreatedOn + "\"");
                                stringWriter.WriteLine(outputRow);
                            }
                            else
                                table.AddCell(new Phrase(response.CreatedOn.ToString(), fonts.Single(f => f.Style == Font.NORMAL)));
                        }
                    }
                    if (thisType == TableType.StringWriter)
                        return stringWriter;
                    else
                        return table;
                }
            }
            return null;
        }

        public string ConvertChars(string chars, Encoding currentEncoding, Encoding desiredEncoding)
        {
            // Create two different encodings
            Encoding defaultCharset = desiredEncoding;
            Encoding altCharset = currentEncoding;

            // Convert the string into a byte[]
            byte[] altCharsetBytes = altCharset.GetBytes(chars);

            // Perform the conversion from one encoding to the other
            byte[] defaultCharsetBytes = Encoding.Convert(altCharset, defaultCharset, altCharsetBytes);

            // Convert the new byte[] into a char[] and then into a string.
            // This is a slightly different approach to converting to illustrate
            // the use of GetCharCount/GetChars
            char[] defaultCharsetChars = new char[defaultCharset.GetCharCount(defaultCharsetBytes, 0, defaultCharsetBytes.Length)];
            defaultCharset.GetChars(defaultCharsetBytes, 0, defaultCharsetBytes.Length, defaultCharsetChars, 0);
            var defaultCharsetString = new string(defaultCharsetChars);

            return defaultCharsetString;
        }

        [Authorize]
        [HttpGet]
        public FileStreamResult Export(Guid id, string exportFormat)
        {
            var thisForm = dbForm.GetFormByKey(id);

            string contentType; // Will be set in switch block to reflect output header

            switch (exportFormat)
            {
                #region CSV output ////////////////////////////
                case "csv":

                    Response.ContentType = "text/csv"; // "application/vnd.ms-excel";
                    Response.AddHeader("content-disposition", "attachment;filename=Spreadsheet.csv");
                    // Try Unicode for special characters
                    Response.ContentEncoding = Encoding.GetEncoding("utf-8"); // Not needed for Excel FYI
                    Response.Buffer = true;
                    Response.Clear();
                    var chars = BuildTable(id, TableType.StringWriter).ToString();
                    // var convertedChars = ConvertChars(chars, Encoding.GetEncoding(1252), Encoding.GetEncoding("iso-8859-7"));
                    Response.Write(chars);
                    Response.End();

                    contentType = "text/csv";

                    break;

                #endregion

                #region PDF output ////////////////////////////

                case "pdf":

                    var memoryStream = new MemoryStream();

                    //-------------------------------------------------------------------------------------------------------------
                    // PDF conversion is provided by iTextSharp, located at http://sourceforge.net/projects/itextsharp/
                    // License is provided by the GNU Affero GPL: http://www.gnu.org/licenses/agpl-3.0.html (no modifications made)
                    // As per the license terms, the original source of iTextSharp may be downloaded at the following URL:
                    // http://sourceforge.net/projects/itextsharp/files/itextsharp/iTextSharp-5.0.2/itextsharp-5.0.2.zip/download
                    //-------------------------------------------------------------------------------------------------------------

                    var document = new Document();
                    PdfWriter.GetInstance(document, memoryStream);
                    document.Open();

                    // Todo: Reference for how to add header image
                    // Image headerlogo = Image.GetInstance("C:\\Temp\\citylogo.png");
                    // document.Add(headerlogo);

                    // Create the fonts
                    var fonts = new List<Font>();

                    var helveticaNormal = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
                    var fontNormal = new Font(helveticaNormal, 12, Font.NORMAL);
                    var fontBold = new Font(helveticaNormal, 12, Font.BOLD);
                    var fontItalic = new Font(helveticaNormal, 12, Font.ITALIC);
                    var fontH1 = new Font(helveticaNormal, 16, Font.BOLD);
                    var fontH2 = new Font(helveticaNormal, 15, Font.NORMAL);

                    fonts.Add(fontNormal);
                    fonts.Add(fontBold);
                    fonts.Add(fontItalic);

                    document.Add(new Paragraph("Frontdesk Export", fontH1));
                    document.Add(new Paragraph(@"Entries from '" + thisForm.Name + "'", fontH2));

                    document.Add(new Paragraph("\n")); // Todo: better newline options?

                    var table = (PdfPTable)BuildTable(id, TableType.PdfPTable, fonts);

                    document.Add(table);
                    document.Close();

                    Response.ContentType = "application/pdf";
                    Response.AddHeader("content-disposition", "attachment;filename=Spreadsheet.pdf");
                    Response.Buffer = true;
                    Response.Clear();
                    Response.OutputStream.Write(memoryStream.GetBuffer(), 0, memoryStream.GetBuffer().Length);
                    Response.OutputStream.Flush();
                    Response.End();

                    contentType = "application/pdf";

                    break;

                #endregion

                default:
                    contentType = null;
                    break;
            }

            return new FileStreamResult(Response.OutputStream, contentType);
        }

        #endregion

        #region Action: GetTag ////////////////////////////

        [Authorize]
        [HttpGet]
        public ViewResult GetTag(Guid id)
        {
            ViewData["Domain"] = ConfigurationManager.AppSettings.Get("AppDomain") + ConfigurationManager.AppSettings.Get("AppRootPath");
            ViewData["DomainShort"] = ConfigurationManager.AppSettings.Get("AppDomainShort") + ConfigurationManager.AppSettings.Get("AppRootPath");
            ViewData["FormKey"] = id;
            var thisForm = dbForm.GetFormByKey(id);
            ViewData["ShortPath"] = thisForm.ShortPath;
            return View();
        }

        #endregion

        #region Action: Ajax ////////////////////////////

        [Authorize]
        [HttpGet]
        // AjaxViewResult is a custom WebUI.Helper class
        // Todo: The client-side validation isn't updating correctly when a new user-control is added via Ajax -
        // - Sanderson's AjaxViewResult.cs contained a method to refresh these for MS-validation but not jQuery...
        public ActionResult AddFormField(string formId, Guid formKey)
        {
            // Todo: consider adding a custom control per form field type (fields like "options" could become conditional)
            ViewData["FormKey"] = formKey;
            ViewData["FieldTypes"] = dbForm.GetFieldTypes();
            return PartialView("form_field", new FormField());
            // AjaxViewResult("form_field", new FormField(), ViewData) { UpdateValidationForFormId = formId };
        }

        #endregion

    }
}
